#include "cornerfind_plugin.h"

#include "ui_plugin.h"


#define         HARRIS_PAGE         0
#define         SHITOMASI_PAGE      1
#define         SUBPIEXL_PAGE       2
#define         CUSHARRIS_PAGE      3

Cornerfind_Plugin::Cornerfind_Plugin()
{
    // Insert initialization codes here ...
}

Cornerfind_Plugin::~Cornerfind_Plugin()
{
    // Insert cleanup codes here ...
}

QString Cornerfind_Plugin::title()
{
    return this->metaObject()->className();
}

QString Cornerfind_Plugin::version()
{
    return "1.0.0";
}

QString Cornerfind_Plugin::description()
{
    return "A <b>Template</b> plugin";
}

QString Cornerfind_Plugin::help()
{
    return "This is a <b>Template</b> plugin. Clone and use it to create new plugins.";
}

void Cornerfind_Plugin::setupUi(QWidget *parent)
{
    ui = new Ui::PluginGui;
    ui->setupUi(parent);

    ui->tabWidget->setCurrentIndex(0);
    connect(ui->tabWidget,SIGNAL(currentChanged(int)),this,SLOT(on_tabWidget_currentChanged(int)));

    connect(ui->blocksizeSpin,SIGNAL(valueChanged(int)),this,SLOT(on_blocksizeSpin_valueChanged(int)));
    connect(ui->ksizeSpin,SIGNAL(valueChanged(int)),this,SLOT(on_ksizeSpin_valueChanged(int)));
    connect(ui->kSpin,SIGNAL(valueChanged(double)),this,SLOT(on_kSpin_valueChanged(double)));
    connect(ui->threshSlider,SIGNAL(valueChanged(int)),this,SLOT(on_threshSlider_valueChanged(int)));

    connect(ui->maxCornerSpin,SIGNAL(valueChanged(int)),this,SLOT(on_maxCornerSpin_valueChanged(int)));
    connect(ui->qualitySpin,SIGNAL(valueChanged(double)),this,SLOT(on_qualitySpin_valueChanged(double)));
    connect(ui->minDstSpin,SIGNAL(valueChanged(double)),this,SLOT(on_minDstSpin_valueChanged(double)));
    connect(ui->shiBlockSizeSpin,SIGNAL(valueChanged(int)),this,SLOT(on_shiBlockSizeSpin_valueChanged(int)));
    connect(ui->ShikSpin,SIGNAL(valueChanged(double)),this,SLOT(on_ShikSpin_valueChanged(double)));
    connect(ui->harrisCheckBox,SIGNAL(toggled(bool)),this,SLOT(on_harrisCheckBox_toggled(bool)));

    connect(ui->subMaxCornerSpin,SIGNAL(valueChanged(int)),this,SLOT(on_subMaxCornerSpin_valueChanged(int)));
    connect(ui->subQualitySpin,SIGNAL(valueChanged(double)),this,SLOT(on_subQualitySpin_valueChanged(double)));
    connect(ui->subMinDstSpin,SIGNAL(valueChanged(double)),this,SLOT(on_subMinDstSpin_valueChanged(double)));
    connect(ui->subBlockSizeSpin,SIGNAL(valueChanged(int)),this,SLOT(on_subBlockSizeSpin_valueChanged(int)));
    connect(ui->SubkSpin,SIGNAL(valueChanged(double)),this,SLOT(on_SubkSpin_valueChanged(double)));
    connect(ui->subMaxCountSpin,SIGNAL(valueChanged(int)),this,SLOT(on_subMaxCountSpin_valueChanged(int)));
    connect(ui->subEpsSpin,SIGNAL(valueChanged(double)),this,SLOT(on_subEpsSpin_valueChanged(double)));
    connect(ui->subWinXSpin,SIGNAL(valueChanged(int)),this,SLOT(on_subWinXSpin_valueChanged(int)));
    connect(ui->subWinYSpin,SIGNAL(valueChanged(int)),this,SLOT(on_subWinYSpin_valueChanged(int)));
    connect(ui->subZeroXSpin,SIGNAL(valueChanged(int)),this,SLOT(on_subZeroXSpin_valueChanged(int)));
    connect(ui->subZeroYSpin,SIGNAL(valueChanged(int)),this,SLOT(on_subZeroYSpin_valueChanged(int)));
    connect(ui->subHarrisCheckBox,SIGNAL(toggled(bool)),this,SLOT(on_subHarrisCheckBox_toggled(bool)));

    connect(ui->cusHblockSpin,SIGNAL(valueChanged(int)),this,SLOT(on_cusHblockSpin_valueChanged(int)));
    connect(ui->cusHksizeSpin,SIGNAL(valueChanged(int)),this,SLOT(on_cusHksizeSpin_valueChanged(int)));
    connect(ui->cusHkSpin,SIGNAL(valueChanged(double)),this,SLOT(on_cusHkSpin_valueChanged(double)));
    connect(ui->cusHmaxcountSpin,SIGNAL(valueChanged(int)),this,SLOT(on_cusHmaxcountSpin_valueChanged(int)));
    connect(ui->cusHSlider,SIGNAL(valueChanged(int)),this,SLOT(on_cusHSlider_valueChanged(int)));
    connect(ui->cusHarrisRadio,SIGNAL(toggled(bool)),this,SLOT(on_cusHarrisRadio_toggled(bool)));
    connect(ui->cusShiToRadio,SIGNAL(toggled(bool)),this,SLOT(on_cusShiToRadio_toggled(bool)));

}

void Cornerfind_Plugin::processImage(const cv::Mat &inputImage, cv::Mat &outputImage)
{
    using namespace std;
    using namespace cv;
    Mat gray;
    outputImage = inputImage.clone();
    cvtColor(inputImage, gray, COLOR_BGR2GRAY);
    switch(ui->tabWidget->currentIndex()){
        case HARRIS_PAGE:{
            Mat dst, norm_dst, normScaleDst;
            dst = Mat::zeros(gray.size(), CV_32FC1);

            cornerHarris(gray, dst, ui->blocksizeSpin->value(),ui->ksizeSpin->value(), ui->kSpin->value());
            normalize(dst, norm_dst, 0, 255, NORM_MINMAX, CV_32FC1, Mat());
            convertScaleAbs(norm_dst, normScaleDst);

            for (int row = 0; row < outputImage.rows; row++) {
                uchar* currentRow = normScaleDst.ptr(row);
                for (int col = 0; col < outputImage.cols; col++) {
                    int value = static_cast<int>(*currentRow);
                    if (value > ui->threshSlider->value()) {
                        circle(outputImage, Point(col, row), 2, Scalar(0, 0, 255), 2, 8, 0);
                    }
                    currentRow++;
                }
            }

            break;
        }
        case SHITOMASI_PAGE:{

            vector<Point2f> corners;

            if(ui->harrisCheckBox->isChecked()){
                goodFeaturesToTrack(gray, corners, ui->maxCornerSpin->value(), ui->qualitySpin->value(),
                                ui->minDstSpin->value(), Mat(), ui->shiBlockSizeSpin->value(),
                                true, ui->ShikSpin->value());
            }
            else{
                goodFeaturesToTrack(gray, corners, ui->maxCornerSpin->value(), ui->qualitySpin->value(),
                        ui->minDstSpin->value(), Mat(), ui->shiBlockSizeSpin->value());
            }

            ui->shiDetecLabel->setText(tr("Detecting %1 Corners").arg(corners.size()));
            for (size_t t = 0; t < corners.size(); t++) {
                circle(outputImage, corners[t], 2, Scalar(255, 0, 0), 2, 8, 0);
            }
            break;
        }
        case SUBPIEXL_PAGE:{

            vector<Point2f> corners;

            if(ui->subHarrisCheckBox->isChecked()){
                goodFeaturesToTrack(gray, corners, ui->subMaxCornerSpin->value(), ui->subQualitySpin->value(),
                                ui->subMinDstSpin->value(), Mat(), ui->subBlockSizeSpin->value(),
                                true, ui->SubkSpin->value());
            }
            else{
                goodFeaturesToTrack(gray, corners, ui->subMaxCornerSpin->value(), ui->subQualitySpin->value(),
                                ui->subMinDstSpin->value(), Mat(), ui->subBlockSizeSpin->value());

            }

            ui->subDetecLabel->setText(tr("Detecting %1 Corners").arg(corners.size()));
            TermCriteria tc = TermCriteria(TermCriteria::EPS + TermCriteria::MAX_ITER,
                                           ui->subMaxCountSpin->value(), ui->subEpsSpin->value());
            Size winSize = Size(ui->subWinXSpin->value(), ui->subWinYSpin->value());
            Size zerozone = Size(ui->subZeroXSpin->value(), ui->subZeroYSpin->value());
            cornerSubPix(gray, corners, winSize, zerozone, tc);

            for (size_t t = 0; t < corners.size(); t++) {
                circle(outputImage, corners[t], 2, Scalar(0, 0, 255), 2, 8, 0);
            }
            ui->showXYText->clear();
            for (size_t t = 0; t < corners.size(); t++) {
                cout << (t + 1) << " (" << corners[t].x << " , " << corners[t].y <<")"<< endl;
                ui->showXYText->append(tr("%1  Point(%2 , %3)<br>").arg(t+1).arg(corners[t].x).arg(corners[t].y));
            }

            break;
        }

        case CUSHARRIS_PAGE:{
            if(ui->cusHarrisRadio->isChecked()){

                Mat harris_dst, harrisRspImg;
                double harris_min_rsp;
                double harris_max_rsp;
                harris_dst = Mat::zeros(inputImage.size(), CV_32FC(6));
                harrisRspImg = Mat::zeros(inputImage.size(), CV_32FC1);
                cornerEigenValsAndVecs(gray, harris_dst, ui->cusHblockSpin->value(), ui->cusHksizeSpin->value());

                for (int row = 0; row < harris_dst.rows; row++) {
                    for (int col = 0; col < harris_dst.cols; col++) {
                        double lambda1 =harris_dst.at<Vec6f>(row, col)[0];
                        double lambda2 = harris_dst.at<Vec6f>(row, col)[1];
                        harrisRspImg.at<float>(row, col) = lambda1*lambda2 - ui->cusHkSpin->value()*pow((lambda1 + lambda2), 2);
                    }
                }
                minMaxLoc(harrisRspImg, &harris_min_rsp, &harris_max_rsp, 0, 0, Mat());
                float t = harris_min_rsp + (((double)ui->cusHSlider->value()) / ui->cusHmaxcountSpin->value())*(harris_max_rsp - harris_min_rsp);
                for (int row = 0; row < inputImage.rows; row++) {
                    for (int col = 0; col < inputImage.cols; col++) {
                        float v = harrisRspImg.at<float>(row, col);
                        if (v > t) {
                            circle(outputImage, Point(col, row), 2, Scalar(0, 0, 255), 2, 8, 0);
                        }
                    }
                }
            }
            else if(ui->cusShiToRadio->isChecked()){

                Mat shiTomasiRsp;
                double shitomasi_max_rsp;
                double shitomasi_min_rsp;
                shiTomasiRsp = Mat::zeros(inputImage.size(), CV_32FC1);
                cornerMinEigenVal(gray, shiTomasiRsp, ui->cusHblockSpin->value(), ui->cusHksizeSpin->value());
                minMaxLoc(shiTomasiRsp, &shitomasi_min_rsp, &shitomasi_max_rsp, 0, 0, Mat());
                float t = shitomasi_min_rsp + (((double)ui->cusHSlider->value()) / ui->cusHmaxcountSpin->value())*(shitomasi_max_rsp - shitomasi_min_rsp);
                for (int row = 0; row < inputImage.rows; row++) {
                    for (int col = 0; col < inputImage.cols; col++) {
                        float v = shiTomasiRsp.at<float>(row, col);
                        if (v > t) {
                            circle(outputImage, Point(col, row), 2, Scalar(0, 0, 255), 2, 8, 0);
                        }
                    }
                }
            }

            break;
        }
        default:
            break;
    }
}


void Cornerfind_Plugin::on_tabWidget_currentChanged(int index)
{
    Q_UNUSED(index);
    emit updateNeeded();
}

void Cornerfind_Plugin::on_blocksizeSpin_valueChanged(int arg1)
{
    Q_UNUSED(arg1);
    emit updateNeeded();
}

void Cornerfind_Plugin::on_ksizeSpin_valueChanged(int arg1)
{
    Q_UNUSED(arg1);
    emit updateNeeded();
}

void Cornerfind_Plugin::on_kSpin_valueChanged(double arg1)
{
    Q_UNUSED(arg1);
    emit updateNeeded();
}

void Cornerfind_Plugin::on_threshSlider_valueChanged(int value)
{
    ui->threshLabel->setText(QString::number(value));
    emit updateNeeded();
}


void Cornerfind_Plugin::on_maxCornerSpin_valueChanged(int arg1)
{
    Q_UNUSED(arg1);
    emit updateNeeded();
}

void Cornerfind_Plugin::on_qualitySpin_valueChanged(double arg1)
{
    Q_UNUSED(arg1);
    emit updateNeeded();
}

void Cornerfind_Plugin::on_minDstSpin_valueChanged(double arg1)
{
    Q_UNUSED(arg1);
    emit updateNeeded();
}

void Cornerfind_Plugin::on_shiBlockSizeSpin_valueChanged(int arg1)
{
    Q_UNUSED(arg1);
    emit updateNeeded();
}

void Cornerfind_Plugin::on_ShikSpin_valueChanged(double arg1)
{
    Q_UNUSED(arg1);
    emit updateNeeded();
}

void Cornerfind_Plugin::on_harrisCheckBox_toggled(bool checked)
{
    //Q_UNUSED(checked);
    if(checked)
        ui->ShikSpin->setEnabled(true);
    else
        ui->ShikSpin->setEnabled(false);
    emit updateNeeded();
}


void Cornerfind_Plugin::on_subMaxCornerSpin_valueChanged(int arg1)
{
    Q_UNUSED(arg1);
    emit updateNeeded();
}

void Cornerfind_Plugin::on_subQualitySpin_valueChanged(double arg1)
{
    Q_UNUSED(arg1);
    emit updateNeeded();
}

void Cornerfind_Plugin::on_subMinDstSpin_valueChanged(double arg1)
{
    Q_UNUSED(arg1);
    emit updateNeeded();
}

void Cornerfind_Plugin::on_subBlockSizeSpin_valueChanged(int arg1)
{
    Q_UNUSED(arg1);
    emit updateNeeded();
}

void Cornerfind_Plugin::on_SubkSpin_valueChanged(double arg1)
{
    Q_UNUSED(arg1);
    emit updateNeeded();
}

void Cornerfind_Plugin::on_subMaxCountSpin_valueChanged(int arg1)
{
    Q_UNUSED(arg1);
    emit updateNeeded();
}

void Cornerfind_Plugin::on_subEpsSpin_valueChanged(double arg1)
{
    Q_UNUSED(arg1);
    emit updateNeeded();
}

void Cornerfind_Plugin::on_subWinXSpin_valueChanged(int arg1)
{
    Q_UNUSED(arg1);
    emit updateNeeded();
}

void Cornerfind_Plugin::on_subWinYSpin_valueChanged(int arg1)
{
    Q_UNUSED(arg1);
    emit updateNeeded();
}

void Cornerfind_Plugin::on_subZeroXSpin_valueChanged(int arg1)
{
    Q_UNUSED(arg1);
    emit updateNeeded();
}

void Cornerfind_Plugin::on_subZeroYSpin_valueChanged(int arg1)
{
    Q_UNUSED(arg1);
    emit updateNeeded();
}

void Cornerfind_Plugin::on_subHarrisCheckBox_toggled(bool checked)
{
    //Q_UNUSED(checked);
    if(checked)
        ui->SubkSpin->setEnabled(true);
    else
        ui->SubkSpin->setEnabled(false);
    emit updateNeeded();
}

void Cornerfind_Plugin::on_cusHblockSpin_valueChanged(int arg1)
{
    Q_UNUSED(arg1);
    emit updateNeeded();
}

void Cornerfind_Plugin::on_cusHksizeSpin_valueChanged(int arg1)
{
    Q_UNUSED(arg1);
    emit updateNeeded();
}

void Cornerfind_Plugin::on_cusHkSpin_valueChanged(double arg1)
{
    Q_UNUSED(arg1);
    emit updateNeeded();
}

void Cornerfind_Plugin::on_cusHmaxcountSpin_valueChanged(int arg1)
{
    Q_UNUSED(arg1);
    emit updateNeeded();
}

void Cornerfind_Plugin::on_cusHSlider_valueChanged(int value)
{
     ui->cusHqlevelLabel->setText(QString::number(value));
    emit updateNeeded();
}

void Cornerfind_Plugin::on_cusHarrisRadio_toggled(bool checked)
{
    Q_UNUSED(checked);
    emit updateNeeded();
}

void Cornerfind_Plugin::on_cusShiToRadio_toggled(bool checked)
{
    Q_UNUSED(checked);
    emit updateNeeded();
}
